use std::{collections::HashMap, fmt::format};

fn main() {
    test_map();
}

// 数组是基本数据类型，分配在栈上
fn test_array() {
    let a = [1, 2, 3];
    
    let b = [3; 5];  // 初始化某个值重复出现n次的数组
    // 该方式初始化非基础类型, 会深拷贝String 5次, 但String没实现Copy特征
    // let c = [String::from("a"); 5]; 

    let c: [String; 5] = std::array::from_fn(|i| format!("{}{}", "idx", i));

    // 数组切片引用, 创建代价小, 只是对底层数组的引用，类似&str
    // 切片类型 [T] 大小不固定， 切片类型的引用 &[T] 拥有固定大小
    // 因为切片是运行期的数据结构，无法确定大小
    let s1 = &a[1..2];
    
    // 数组类型用 [T; n] 表示, 长度也是类型的一部分
    let aa = [1, 2]; // [i32; 2] 和 [i32; 3]类型不同
}

fn test_vec() {
    let mut v1: Vec<i32> = Vec::new();
    let v2 = vec![1, 2, 3];

    // 修改动态数组要mut
    v1.push(1);

    // 持有不可变引用
    let value = &v1[0];
    // v1.push(5); panic, 不可同时持有可变引用 和 不可变引用
    println!("vec: {}", value);
    
    match v1.get(1) {
        Some(v) => println!("the element:{}", v),
        None => println!("not found")
    }
}

// 字符串  String
// 字符串切片  &str
//   1. 可由 &String[idx1...idx2] 创建
//   2. 字符串字面量是切片 (指向了程序可执行文件中的某个点)
fn test_str() {
    // &str ==> String
    let s1 = String::from("aaa");

    let data = "hello world";
    let mut s1 = data.to_string();

    // String ==> &str
    let _ = s1.as_str();

    // 解引用强制转换, Deref特征
    // &String能转成&str, &s2转成&s2[..]
    let s2 = String::from("bar");
    s1.push_str(&s2);

    // string 和 &str 拼接
    // 获取了s1的所有权, s1已经被移动，不能再使用
    let s3 = s1 + &s2;
    println!("{}", s3);

    // format宏不会获取参数的所有权
    let s4 = format!("{} - {}", s2, s3);

    // 遍历字符串
    for c in s4.chars() {
        print!("{}", c)
    }
}

fn test_map() {
    let mut m: HashMap<String, i32> = HashMap::new();
    
    let k = String::from("blue");
    let v = 100;
    // 获取了string的所有权
    // i32实现了copy trait，值会被复制到hashmap中
    m.insert(k, v);
    //println!("key:{} value:{}", k, v) // panic

    let mut m2: HashMap<&str, i32> = HashMap::new();
    let k2 = "yellow";
    m2.insert(k2, v);
    println!("key:{}", k2)
}